package com.flute.icrawler.policy.updatepolicy.util;

import java.util.List;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * w3c DOM 工具类
 * 
 * @author wangbin
 * 
 */
public class DOMUtil {

	private static final XPath XPATH = XPathFactory.newInstance().newXPath();

	/**
	 * 获取DOM的html
	 * 
	 * @param node
	 * @param buffer
	 */
	public static String transform(Node node) {
		StringBuffer buffer = new StringBuffer();
		transform(node, buffer, null, null);
		return buffer.toString();
	}

	/**
	 * 获取Node的html(过滤不需要的nodes)
	 * 
	 * @param node
	 * @param filterTag
	 * @return
	 */
	public static String transform(Node node, List<String> filterTags, List<String> filterAttrs) {
		StringBuffer buffer = new StringBuffer();
		transform(node, buffer, filterTags, filterAttrs);
		return buffer.toString();
	}

	/**
	 * 得到html节点的text
	 * 
	 * @param node
	 * @param buffer
	 */
	public static String getNodeValue(Node node, List<String> filterTags) {
		StringBuffer buffer = new StringBuffer();
		getNodeValue(node, buffer, filterTags);
		return buffer.toString();
	}

	/**
	 * 得到html节点的text
	 * 
	 * @param node
	 * @return
	 */
	public static String getNodeValue(Node node) {
		StringBuffer buffer = new StringBuffer();
		getNodeValue(node, buffer, null);
		return buffer.toString();
	}

	/**
	 * 
	 * @param node
	 * @param buffer
	 */
	private static void transform(Node node, StringBuffer buffer, List<String> filterTags, List<String> filterAttrs) {
		if (node.getNodeType() == Node.TEXT_NODE) {
			String text = node.getNodeValue();
			if (text != null && !text.trim().equals("")) {
				buffer.append(text.trim());
			}
		} else if (node.getNodeType() == Node.ELEMENT_NODE) {
			String tag = node.getNodeName().toUpperCase();
			if (filterTags != null && filterTags.contains(tag)) {
				return;
			}
			buffer.append("<").append(tag);
			NamedNodeMap attrs = node.getAttributes();
			for (int i = 0; i < attrs.getLength(); i++) {
				Node attr = attrs.item(i);
				String attrName = attr.getNodeName().toLowerCase();
				if (filterAttrs != null && filterAttrs.contains(attrName)) {
					continue;
				}
				buffer.append(" ").append(attrName).append("='").append(attr.getNodeValue()).append("'");
			}
			buffer.append(">");
			if (node.hasChildNodes()) {
				NodeList nodes = node.getChildNodes();
				for (int i = 0; i < nodes.getLength(); i++) {
					transform(nodes.item(i), buffer, filterTags, filterAttrs);
				}
			}
			buffer.append("</").append(tag).append(">");
		} else if (node.getNodeType() == Node.DOCUMENT_NODE) {
			transform(((Document) node).getDocumentElement(), buffer, filterTags, filterAttrs);
		} else if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
			buffer.append(node.getNodeValue());
		}
	}

	/**
	 * 
	 * @param node
	 * @param buffer
	 */
	private static void getNodeValue(Node node, StringBuffer buffer, List<String> filterTags) {
		if (node.getNodeType() == Node.TEXT_NODE) {
			String value = node.getNodeValue();
			if (value != null && !value.trim().equals("")) {
				buffer.append(node.getNodeValue().trim());
			}
		} else if (node.getNodeType() == Node.ELEMENT_NODE) {
			Element element = (Element) node;
			String tag = element.getTagName().toUpperCase();
			if (filterTags != null && filterTags.contains(tag)) {
				return;
			}
			if (node.hasChildNodes()) {
				NodeList nodes = node.getChildNodes();
				for (int i = 0; i < nodes.getLength(); i++) {
					Node child = nodes.item(i);
					getNodeValue(child, buffer, filterTags);
				}
			}
		} else if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
			String text = node.getNodeValue();
			if (text != null) {
				buffer.append(text);
			}
		} else if (node.getNodeType() == Node.DOCUMENT_NODE) {
			getNodeValue(((Document) node).getDocumentElement(), buffer, filterTags);
		} else {
			return;
		}
	}

	/**
	 * xpath 匹配节点
	 * 
	 * @param doc
	 * @param xpath
	 * @return
	 * @throws XPathExpressionException
	 */
	public static NodeList xpath(Document doc, String xpath) throws XPathExpressionException {
		return (NodeList) XPATH.evaluate(xpath, doc, XPathConstants.NODESET);
	}
}
